package com.yungu.swift.order.utils;


import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dyplsapi.model.v20170525.*;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.profile.DefaultProfile;
import com.yungu.swift.order.model.dto.OrderSecretNoDto;
import com.yungu.swift.utils.DateUtils;
import com.yungu.swift.utils.JsonUtils;
import com.yungu.swift.utils.ParamUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.yungu.swift.order.config.NacosListener.ALIYUN_CONFIG;

/**
 * Created by cuixiuyin on 2019/1/2.
 */
@Slf4j
@Component
public class SecretNoUtils {

    private static final String REGION_ID = "cn-hangzhou";
    /**
     * 产品名称:云通信隐私保护产品,开发者无需替换
     */
    private static final String PRODUCT = "Dyplsapi";
    /**
     * 产品域名,开发者无需替换
     */
    private static final String DOMAIN = "dyplsapi.aliyuncs.com";

    private static String accessKey = "";
    private static String secretKey = "";
    private static String poolKey;
    private static IAcsClient acsClient;
    private static Map<String, String> errorMap = new HashMap<>(32);

    @Value("swift.aliyun.accessKey")
    public void setAccessKey(String accessKey) {
        SecretNoUtils.accessKey = accessKey;
    }

    @Value("swift.aliyun.secretKey")
    public void setSecretKey(String secretKey) {
        SecretNoUtils.secretKey = secretKey;
    }

    static {
        accessKey = ParamUtil.defaultIfNull(accessKey, ALIYUN_CONFIG.getAccessKeyId());
        secretKey = ParamUtil.defaultIfNull(secretKey, ALIYUN_CONFIG.getAccessKeySecret());
        poolKey = ALIYUN_CONFIG.getSecretNoPoolKey();
        DefaultProfile.addEndpoint("cn-hangzhou", PRODUCT, DOMAIN);
        //初始化acsClient,暂不支持region化
        acsClient = new DefaultAcsClient(DefaultProfile.getProfile(REGION_ID, accessKey, secretKey));

        errorMap.put("isp.RAM_PERMISSION_DENY", "阿里云RAM权限DENY");
        errorMap.put("isv.OUT_OF_SERVICE", "业务停机");
        errorMap.put("isv.PRODUCT_UN_SUBSCRIPT", "未开通云通信产品的阿里云客户");
        errorMap.put("isv.PRODUCT_UNSUBSCRIBE", "产品未开通");
        errorMap.put("isv.ACCOUNT_NOT_EXISTS", "账户不存在");
        errorMap.put("isv.ACCOUNT_ABNORMAL", "账户异常");
        errorMap.put("isp.SYSTEM_ERROR", "系统错误");
        errorMap.put("isp.UNKNOWN_ERR_CODE", "运营商未知错误");
        errorMap.put("isv.PARTNER_NOT_EXIST", "未知合作伙伴");
        errorMap.put("isv.NO_NOT_EXIST", "号码不存在");
        errorMap.put("isv.ILLEGAL_ARGUMENT", "参数非法");
        errorMap.put("isp.DAO_EXCEPTION", "数据库异常");
        errorMap.put("isv.NO_AVAILABLE_NUMBER", "无可用号码");
        errorMap.put("isp.VENDOR_UNAVAILABLE", "运营商降级");
        errorMap.put("isv.FLOW_LIMIT", "业务流控");
        errorMap.put("isv.PARTNER_IS_CLOSED", "partner被关停");
        errorMap.put("isv.FORBIDDEN_ACTION", "无权操作");
        errorMap.put("isv.NO_USED_BY_OTHERS", "码被其他业务方占用");
        errorMap.put("isv.VENDOR_BIND_FAILED", "运营商绑定失败");
        errorMap.put("isv.EXPIRE_DATE_ILLEGAL", "过期时间非法");
        errorMap.put("isv.MOBILE_NUMBER_ILLEGAL", "号码格式非法");
        errorMap.put("isv.BIND_CONFLICT", "绑定冲突");
    }

    /**
     * AXB绑定
     *
     * @return
     * @throws
     */
    public static BindAxbResponse.SecretBindDTO bindAxb(OrderSecretNoDto secretNoDto) {
        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");
        try {
            //组装请求对象-具体描述见控制台-文档部分内容
            BindAxbRequest request = new BindAxbRequest();
            //必填:对应的号池Key
            request.setPoolKey(poolKey);
            //必填:AXB关系中的A号码
            request.setPhoneNoA(secretNoDto.getPassengerMobile());
            //必填:AXB关系中的B号码
            request.setPhoneNoB(secretNoDto.getDriverMobile());
            //必填:绑定关系对应的失效时间-不能早于当前系统时间
            request.setExpiration(DateUtils.format(secretNoDto.getFailureTime()));
            //可选:是否需要录制音频-默认是false
            request.setIsRecordingEnabled(ALIYUN_CONFIG.getRecording());
            //外部业务自定义ID属性
            Map<String, String> extMap = new HashMap<>();
            extMap.put("orderUuid", secretNoDto.getOrderUuid());
            extMap.put("appid", secretNoDto.getAppid());
            request.setOutId(JsonUtils.writeJsonStr(extMap));
            //hint 此处可能会抛出异常，注意catch
            BindAxbResponse response = acsClient.getAcsResponse(request);
            if ("OK".equals(response.getCode())) {
                return response.getSecretBindDTO();
            } else {
                log.info("订单:{},乘客号码：{},新增绑定异常：原因：{}", secretNoDto.getOrderUuid(), secretNoDto.getPassengerMobile(),
                        getErrorMsg(response.getCode()));
            }
        } catch (Exception e) {
            log.error("隐私号绑定异常, passengerMobile:{}", secretNoDto.getPassengerMobile(), e);
        }
        return null;
    }

    /**
     * 更新绑定关系 更新司机号码  updateNoB
     */
    public static Boolean updateNoB(OrderSecretNoDto orderSecretNoDto) {
        //设置超时时间-可自行调整
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");
        try {
            //组装请求对象-具体描述见控制台-文档部分内容
            UpdateSubscriptionRequest request = new UpdateSubscriptionRequest();
            //绑定关系对应的号池Key
            request.setPoolKey(poolKey);
            //必填:绑定关系ID
            request.setSubsId(orderSecretNoDto.getPrivacyUuid());
            //必填:绑定关系对应的X号码
            request.setPhoneNoX(orderSecretNoDto.getPrivacyMobile());
            //必填:操作类型指令支持,支持的操作类型详见文档
            request.setOperateType("updateNoB");
            //可选:需要修改的B号码
            request.setPhoneNoB(orderSecretNoDto.getDriverMobile());
            //hint 此处可能会抛出异常，注意catch
            UpdateSubscriptionResponse response = acsClient.getAcsResponse(request);
            if ("OK".equals(response.getCode())) {
                return Boolean.TRUE;
            }
            log.info("订单:{} ,更新绑定司机异常：原因：{}", orderSecretNoDto.getOrderUuid(), getErrorMsg(response.getCode()));
        } catch (Exception e) {
            log.error("隐私小号修改司机号异常, orderUuid:{}", orderSecretNoDto.getOrderUuid(), e);
        }
        return Boolean.FALSE;
    }

    /**
     * 更新绑定关系 更新失效时间
     *
     * @return
     * @throws
     */
    public static Boolean updateExpire(OrderSecretNoDto orderSecretNoDto) {
        //设置超时时间-可自行调整
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");
        try {
            //组装请求对象-具体描述见控制台-文档部分内容
            UpdateSubscriptionRequest request = new UpdateSubscriptionRequest();
            //绑定关系对应的号池Key
            request.setPoolKey(poolKey);
            //必填:绑定关系ID
            request.setSubsId(orderSecretNoDto.getPrivacyUuid());
            //必填:绑定关系对应的X号码
            request.setPhoneNoX(orderSecretNoDto.getPrivacyMobile());
            //必填:操作类型指令支持,支持的操作类型详见文档
            request.setOperateType("updateExpire");
            //可选:需要修改的B号码
            request.setExpiration(DateUtils.format(orderSecretNoDto.getFailureTime()));
            //hint 此处可能会抛出异常，注意catch
            UpdateSubscriptionResponse response = acsClient.getAcsResponse(request);
            if ("OK".equals(response.getCode())) {
                return Boolean.TRUE;
            }
            log.info("订单:{},更新绑定时间异常：原因：{}", orderSecretNoDto.getOrderUuid(), getErrorMsg(response.getCode()));
        } catch (Exception e) {
            log.error("隐私小号修改过期时间异常, orderUuid:{}", orderSecretNoDto.getOrderUuid(), e);
        }
        return Boolean.FALSE;
    }


    /**
     * 解绑隐私号
     *
     * @return
     * @throws
     */
    public static void unbind(OrderSecretNoDto orderSecretNoDto) {
        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");
        try {
            //组装请求对象
            UnbindSubscriptionRequest request = new UnbindSubscriptionRequest();
            //必填:对应的号池Key
            request.setPoolKey(poolKey);
            //必填-分配的X小号-对应到绑定接口中返回的secretNo;
            request.setSecretNo(orderSecretNoDto.getPrivacyMobile());
            //可选-绑定关系对应的ID-对应到绑定接口中返回的subsId;
            request.setSubsId(orderSecretNoDto.getPrivacyUuid());
            UnbindSubscriptionResponse response = acsClient.getAcsResponse(request);
            if (!"OK".equals(response.getCode())) {
                log.info("订单:{},解绑异常：原因：{}", orderSecretNoDto.getOrderUuid(), getErrorMsg(response.getCode()));
            }
        } catch (Exception e) {
            log.error("隐私小号解绑异常, orderUuid:{}", orderSecretNoDto.getOrderUuid(), e);
        }
    }


    /**
     * 获得录音下载链接
     *
     * @return
     */
    public static String queryRecordFileDownloadUrl(String callId, Date callTime) {
        QueryRecordFileDownloadUrlRequest request = new QueryRecordFileDownloadUrlRequest();
        request.setCallId(callId);
        request.setCallTime(DateUtils.format(callTime));
        request.setPoolKey(poolKey);
        try {
            QueryRecordFileDownloadUrlResponse acsResponse = acsClient.getAcsResponse(request);
            if ("OK".equals(acsResponse.getCode())) {
                return acsResponse.getDownloadUrl();
            }
            log.warn("callId:{}, callTime:{} 获取录音文件错误:{}", callId, DateUtils.format(callTime), acsResponse.getMessage());
        } catch (ServerException e) {
            log.error("callId:{}, callTime:{} 获取录音文件失败", callId, DateUtils.format(callTime), e);
        } catch (ClientException e) {
            log.error("callId:{}, callTime:{} 获取录音文件失败", callId, DateUtils.format(callTime), e);
        }
        return null;
    }

    private static String getErrorMsg(String errorCode) {
        String errorMsg = errorMap.get(errorCode);
        if (errorMsg == null) {
            errorMsg = "其他错误" + errorCode;
        } else {
            errorMsg = "调用阿里云错误:" + errorMsg;
        }
        return errorMsg;
    }
}
